package com.hxd.qzg.websocket;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hxd.qzg.common.Msg;
import com.hxd.qzg.common.Operation;
import com.hxd.qzg.common.ServiceException;
import com.hxd.qzg.common.UseBox;
import com.hxd.qzg.common.enums.MsgCodeEnum;
import com.hxd.qzg.common.enums.MsgTypeEnum;
import com.hxd.qzg.common.model.BoxLock;
import com.hxd.qzg.common.model.Qz;
import com.hxd.qzg.module.BoxGroupService;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;

import cn.hutool.core.util.IdcardUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;

@ServerEndpoint("/{userId}/msg.ws")
public class WebSocket {
	private static Log logger = LogFactory.get();

	private static final String SBH = "10000";
	private static final Map<Integer, Session> map = new ConcurrentHashMap<Integer, Session>();


	@OnOpen
	public void onOpen(@PathParam("userId") Integer userId, Session session) {
		logger.info("userId {}", userId);
		if (map.get(userId) == null) {
			map.put(userId, session);
		}

	}

	/**
	 * 收到客户端消息时触发
	 */
	@SuppressWarnings("unlikely-arg-type")
	@OnMessage
	public void onMessage(@PathParam("userId") String userId, String jsonStr, Session session) throws IOException {
		// 向客户端返回发送过来的消息
		logger.info("onMessage userId {} ,jsonStr {} ", userId, jsonStr);

		if (map.get(userId) == null) {
			map.put(Integer.valueOf(userId), session);
		}

		Msg msg = checkJson(jsonStr);
		logger.info("checkJson {} ", JSONObject.toJSONString(msg));
		if (msg.getCode() != MsgCodeEnum.SUCCESS.getCode()) {
			session.getBasicRemote().sendText(JSONObject.toJSONString(msg));
			return;
		}

		logger.info("type {} ", msg.getType().intValue());

		String operation=checkOperation(msg,session,userId);
		if (StringUtils.isEmpty(operation)) {
			return;
		}
		switch (msg.getType().intValue()) {

		case 500:
			operation(msg, session, userId, MsgTypeEnum.USE.getCode(), operation);
			break;
		case 1500:
			operation(msg, session, userId, MsgTypeEnum.QZ.getCode(), operation);
			break;
		case 2000:
			operation(msg, session, userId, MsgTypeEnum.SCAN.getCode(), operation);
			break;
		default:
			msg.setCode(MsgCodeEnum.ERR.getCode());
			msg.setMessage("当前操作类选择错误");
			session.getBasicRemote().sendText(JSONObject.toJSONString(msg));
			break;
		}

	}


	private Msg checkJson(String jsonStr) {
		Msg msg = new Msg();
		if (!JSONUtil.isJson(jsonStr)) {
			msg.setCode(MsgCodeEnum.ERR.getCode());
			msg.setMessage("不是json格式");
			return msg;
		}
		try {
			msg = JSONObject.parseObject(jsonStr, Msg.class);
		} catch (Exception e) {
			msg.setCode(MsgCodeEnum.ERR.getCode());
			msg.setMessage("数据格式无法转化");
			return msg;
		}
		if (null == msg.getBoxId()) {
			msg.setCode(MsgCodeEnum.ERR.getCode());
			msg.setMessage("boxId不能为空");
		}
		return msg;
	}



	private String checkOperation(Msg msg, Session session, String userId) throws IOException {
		Operation o = new Operation();
		try {
			o.setBoxId(msg.getBoxId());
			o.setUserId(userId);
			o.setSbh(SBH);
			o.setScanInfo(String.valueOf(msg.getData()));
		} catch (Exception e) {
			msg.setMessage("当前出现异常,无法操作");
			session.getBasicRemote().sendText(JSONObject.toJSONString(msg));
			return null;
		}
		String operationJson = JSONObject.toJSONString(o);
		return operationJson;
	}
	// 拿到这把锁做什么操作
	private void operation(Msg msg, Session session, String userId, Integer code, String operation) throws IOException {
		// 推送发送的消息 1当前柜子可以使用 0不可以使用
		boolean bl = false;
		try {
			bl = new UseBox().operation(userId, msg.getBoxId(), code, operation);
			if (bl) {
				msg.setCode(MsgCodeEnum.SUCCESS.getCode());
				msg.setMessage("当前盒子正在被打开");
				session.getBasicRemote().sendText(JSONObject.toJSONString(msg));
				return;
			}
			msg.setCode(MsgCodeEnum.ERR.getCode());
			msg.setMessage("当前柜子被占用");
			session.getBasicRemote().sendText(JSONObject.toJSONString(msg));
		} catch (Exception e) {
			msg.setCode(MsgCodeEnum.ERR.getCode());
			msg.setMessage("错误未知请联系管理员");
			session.getBasicRemote().sendText(JSONObject.toJSONString(msg));
		}
	}
	
	// 拿到这把锁做什么操作
	public void operation(Msg msg, String userId, Integer code, String operation) throws IOException {

		boolean bl = false;
		try {
			bl = new UseBox().operation(userId, msg.getBoxId(), code, operation);
			if (bl) {
				return;
			}
		} catch (Exception e) {
			throw new ServiceException("客户端 operation 数据保存失败");
		}
	}

	public void qz(Msg msg, Session session, String userId) throws IOException {
		try {
			boolean bl = new BoxGroupService().takeOutCertificate(Integer.valueOf(msg.getBoxId()));
		} catch (Exception e) {
			if (e instanceof ServiceException) {
				msg.setCode(MsgCodeEnum.ERR.getCode());
				msg.setMessage(e.getMessage());
			} else {
				msg.setCode(MsgCodeEnum.ERR.getCode());
				msg.setMessage("错误未知请联系管理员");
			}
			if (session != null) {
				session.getBasicRemote().sendText(JSONObject.toJSONString(msg));

			}
			return;
		}
		
	}

	public void scanSave(Msg msg, Session session, String userId) throws IOException {
		String scanInfo = (String) msg.getData();

		try {
			boolean bl = new BoxGroupService().scanSave(Integer.valueOf(msg.getBoxId()), scanInfo);
		} catch (Exception e) {
			logger.info("scanSave  {}", e.getMessage());
			if (e instanceof ServiceException) {
				msg.setCode(MsgCodeEnum.ERR.getCode());
				msg.setMessage(e.getMessage());
			} else {
				msg.setCode(MsgCodeEnum.ERR.getCode());
				msg.setMessage("错误未知请联系管理员");
			}
			if (session != null) {
				session.getBasicRemote().sendText(JSONObject.toJSONString(msg));

			}
			return;
		}

	}

	/**
	 * 异常时触发
	 */
	@OnError
	public void onError(Throwable throwable, @PathParam("userId") Integer userId, Session session) {
		if (map.get(userId) != null) {
			map.remove(userId);
		}
		
		logger.info("连接异常 userId {} ", userId);

	}

	/**
	 * 关闭连接时触发
	 */
	@OnClose
	public void onClose(Session session, @PathParam("userId") Integer userId) {
		if (map.get(userId) != null) {
			map.remove(userId);
		}
		logger.info("连接关闭了 userId {} ", userId);
	}


	// 通用流程方法 发送关闭柜子信息
	public void onCloseMessage(String ban, String boxNo) throws IOException {
		Record box = Db.findFirst("SELECT * FROM api_box WHERE ban=? and  box_no=?", ban, boxNo);

		Integer boxId = box.getInt("id");
		Qz qz = new Qz();
		qz.setRequest(MsgTypeEnum.CLOSE.getDescription());
		qz.setBoxId(boxId);
		new UseBox().saveQzLog(qz);


		Record record = Db.findFirst("SELECT * FROM api_box_lock WHERE box_id=?", boxId);
		if (null == record) {
			logger.info("api_box_lock boxId {} 记录已经被删除", boxId);
			return;
		}

		String str = record.get("operation");
		Operation operation=null;
		try {
			operation = JSON.parseObject(str, Operation.class);
		} catch (Exception e) {
			logger.info("operation 转化异常 {}", str);
			return;
		}

		String account = record.getStr("lock_account");
		Msg msg = new Msg();
		msg.setType(MsgTypeEnum.CLOSE.getCode());
		msg.setCode(MsgCodeEnum.SUCCESS.getCode());
		msg.setMessage("柜门已经关闭");
		msg.setBoxId(String.valueOf(boxId));

		Session session = null;
		String userId = operation.getUserId();

		int code = record.getInt("code");
		switch (code) {
		case 1500:
			this.qz(msg, session, userId);
			break;
		case 2000:
			this.scanSave(msg, session, userId);
			break;
		default:
			break;
		}
		BoxLock.dao.deleteById(record.getInt("id"));

		// 身份证用户 不发
		if (!IdcardUtil.isValidCard(account)) {
			session = map.get(Integer.valueOf(account));
		}
		// 当前 socket用户不在线 不发
		if (session != null) {
			session.getBasicRemote().sendText(JSONObject.toJSONString(msg));
		}
	}


}